package cn.js.sangu.unitStore.service.async;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.databind.ObjectMapper;
import cn.js.sangu.unitStore.common.constant.SysInfo;
import cn.js.sangu.unitStore.common.exception.ServiceException;
import cn.js.sangu.unitStore.dto.FileListDTO;
import cn.js.sangu.unitStore.dto.MsgDTO;
import cn.js.sangu.unitStore.entity.BomEntity;
import cn.js.sangu.unitStore.entity.FileNas;
import cn.js.sangu.unitStore.service.FileService;
import cn.js.sangu.unitStore.service.process.ExcelService;
import cn.js.sangu.unitStore.service.update.BomUpdateService;
import cn.js.sangu.unitStore.utils.LinsUtil;
import cn.js.sangu.unitStore.websocket.WebSocketService;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class BomAsyncService {

    private final FileService fileService;
    private final ExcelService excelService;
    private final BomUpdateService bomUpdateService;
    private final WebSocketService wService;

    // @Autowired
    public BomAsyncService(
            FileService fileService,
            ExcelService excelService,
            BomUpdateService bomUpdateService,
            WebSocketService wService) {
        this.fileService = fileService;
        this.excelService = excelService;
        this.bomUpdateService = bomUpdateService;
        this.wService = wService;
    }

    static final String ROOT_PATH = System.getProperty("user.dir") + File.separator + "files";
    static String today = cn.hutool.core.date.DateUtil.today();
    static String folderRootPath = ROOT_PATH + File.separator + today + File.separator;

    // 加工文件
    @Async("taskExecutor") // 异步方法
    public void executiveProcess(BomEntity param) {
        long start = System.currentTimeMillis();
        log.info("开始异步处理工具任务，用户ID: {}, BOM ID: {}", param.getCreator(), param.getId());

        // 文件将存储在fileNasList中
        List<FileNas> fileNasList = new ArrayList<>();
        String resultFilePath = null; // 改为存储处理后的文件路径
        String msgType = "fail";
        try {
            // 参数验证
            if (param == null || param.getFileList() == null) {
                throw new ServiceException("BOM实体或文件列表为空");
            }

            ObjectMapper mapper = new ObjectMapper();
            // 转换取出 文件列表
            List<FileListDTO> dtoList = mapper.convertValue(param.getFileList(),
                    mapper.getTypeFactory().constructCollectionType(List.class, FileListDTO.class));

            if (dtoList == null || dtoList.isEmpty()) {
                throw new ServiceException("文件列表为空或格式错误");
            }

            log.info("准备处理 {} 个文件", dtoList.size());

            // 准备处理Excel并获取处理后的文件路径，若处理了多个附件，实际上只返回和存储第一条附件的路径。
            resultFilePath = handleExcelReady(dtoList, fileNasList, param);

            if (resultFilePath == null || resultFilePath.trim().isEmpty()) {
                throw new ServiceException("文件处理失败，未生成结果文件");
            }

            // 在异步里更新加工后路径
            param.setAttachType(resultFilePath); // 修正：使用处理后的文件路径

            // 设置状态为加工成功
            param.setState(SysInfo.ProcessStatusSuccess);

            long end = System.currentTimeMillis();
            long ms = end - start;

            // 优化时间格式化
            String timeStr = formatProcessingTime(ms);
            param.setTakeTime(timeStr);

            log.info("{}：Bom清单任务处理完成，用时: {}，结果文件: {}",
                    Thread.currentThread().getName(), timeStr, resultFilePath);

            // 更新BOM实体
            if (!bomUpdateService.updateBomEntity(param)) {
                throw new ServiceException("BOM实体更新失败");
            }

            // 保存文件记录
            if (!fileNasList.isEmpty()) {
                for (FileNas nas : fileNasList) {
                    if (!fileService.save(nas)) {
                        log.warn("保存文件记录失败: {}", nas.getFileName());
                    }
                }
            }

            msgType = "success";
        } catch (ServiceException e) {
            // 业务异常处理
            log.error("Bom清单任务处理失败: {}", e.getMessage());
            msgType = "fail";
            handleProcessingFailure(param, e.getMessage());
        } catch (Exception e) {
            // 系统异常处理
            log.error("Bom清单任务处理过程中发生系统异常", e);
            msgType = "fail";
            handleProcessingFailure(param, "系统异常: " + e.getMessage());
        } finally {
            // 发送成功通知
            wService.sendMsg(new MsgDTO(param.getCreator().toString(), msgType,
                    String.format("Bom清单任务处理" + msgType)));
        }
    }

    /**
     * 格式化处理时间
     */
    private String formatProcessingTime(long ms) {
        if (ms < 1000) {
            return ms + "毫秒";
        } else {
            long s = ms / 1000;
            if (s < 60) {
                return s + "秒";
            } else if (s < 3600) {
                return s / 60 + "分钟" + (s % 60 > 0 ? s % 60 + "秒" : "");
            } else {
                long h = s / 3600;
                long m = (s % 3600) / 60;
                return h + "小时" + (m > 0 ? m + "分钟" : "");
            }
        }
    }

    /**
     * 处理任务失败
     */
    private void handleProcessingFailure(BomEntity param, String errorMessage) {
        param.setState(SysInfo.ProcessStatusFail);

        try {
            if (!bomUpdateService.updateBomEntity(param)) {
                log.error("更新BOM实体状态为失败时失败");
            }
        } catch (Exception e) {
            log.error("更新BOM实体状态时发生异常", e);
        }

        // 发送失败通知
        wService.sendMsg(new MsgDTO(param.getCreator().toString(), "error", "工具任务处理失败: " + errorMessage));
    }

    // 准备处理Excel
    private String handleExcelReady(List<FileListDTO> dtoList, List<FileNas> fileNasList, BomEntity param)
            throws ServiceException {
        ObjectMapper mapper = new ObjectMapper();

        // 检查文件列表是否为空
        if (dtoList == null || dtoList.isEmpty()) {
            throw new ServiceException("文件列表不能为空");
        }

        // 存储第一个处理后的文件路径作为返回值
        String firstResultPath = null;

        try {
            // 循环处理每个文件DTO
            for (int i = 0; i < dtoList.size(); i++) {
                FileListDTO fileDto = dtoList.get(i);
                if (fileDto == null || fileDto.getResponse() == null || fileDto.getResponse().getData() == null) {
                    log.warn("第{}个文件信息不完整或无效，跳过处理", i + 1);
                    continue;
                }

                // 获取Excel文件路径
                FileNas fileNasData = mapper.convertValue(fileDto.getResponse().getData(), FileNas.class);
                if (fileNasData == null || fileNasData.getFilePath() == null
                        || fileNasData.getFilePath().trim().isEmpty()) {
                    log.warn("第{}个文件路径无效或为空，跳过处理", i + 1);
                    continue;
                }

                String excelPath = fileNasData.getFilePath();
                log.info("开始处理第{}个Excel文件: {}", i + 1, excelPath);

                // 验证原始文件是否存在
                File originalFile = new File(excelPath);
                if (!originalFile.exists()) {
                    log.warn("第{}个原始Excel文件不存在: {}，跳过处理", i + 1, excelPath);
                    continue;
                }

                // 调用Excel处理服务，保存原始数据到数据库
                String resultPath = excelService.dataProcess(excelPath, param);

                // 验证处理结果文件
                File resultFile = new File(resultPath);
                if (!resultFile.exists() || !resultFile.isFile()) {
                    log.warn("第{}个Excel处理结果文件生成失败: {}，跳过处理", i + 1, resultPath);
                    continue;
                }

                if (resultFile.length() == 0) {
                    log.warn("第{}个Excel处理结果文件为空: {}，跳过处理", i + 1, resultPath);
                    continue;
                }

                // 创建新的FileNas对象并设置属性
                FileNas newFileNas = new FileNas();
                newFileNas.setFileName(resultFile.getName());
                newFileNas.setFileSize(LinsUtil.computeFileSize(resultFile.length()));
                newFileNas.setFileType(SysInfo.ToolGeneration);
                newFileNas.setFilePath(resultPath);
                newFileNas.setDownCount(0);
                newFileNas.setParId(null);
                newFileNas.setParPath(null);
                newFileNas.setRemark("工具生成");
                newFileNas.setUserId(param.getCreator());

                // 添加到fileNasList
                fileNasList.add(newFileNas);

                // 记录第一个处理成功的文件路径作为返回值
                if (firstResultPath == null) {
                    firstResultPath = resultPath;
                }

                log.info("第{}个Excel文件处理完成，结果文件: {}", i + 1, resultPath);
            }

            // 检查是否有成功处理的文件
            if (fileNasList.isEmpty()) {
                throw new ServiceException("所有文件处理失败或为空");
            }

            log.info("Excel文件批量处理完成，成功处理 {} 个文件", fileNasList.size());
            return firstResultPath; // 返回第一个处理后的文件路径作为主要结果路径

        } catch (ServiceException e) {
            // 业务异常直接抛出
            log.error("处理Excel文件时发生业务异常: {}", e.getMessage());
            throw e;
        } catch (Exception e) {
            // 其他异常包装为ServiceException
            log.error("处理Excel文件时发生系统异常", e);
            throw new ServiceException("处理Excel文件失败: " + e.getMessage());
        }
    }

    public void test() {
        // excelService.test();
    }

    public void testWs(String uid) {
        wService.sendMsg(new MsgDTO(uid, "test", "工具任务测试消息"));
        // utilsWsHandler.handleTestMessage(new MsgDTO(uid,"test","工具任务测试消息"));
    }

}